package org.ljy.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import org.ljy.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import org.ljy.lotterysystem.common.exception.ServiceException;
import org.ljy.lotterysystem.common.utils.JWTUtil;
import org.ljy.lotterysystem.common.utils.JacksonUtil;
import org.ljy.lotterysystem.common.utils.RedisUtil;
import org.ljy.lotterysystem.common.utils.RegexUtil;
import org.ljy.lotterysystem.controller.UserController;
import org.ljy.lotterysystem.controller.param.ShortMessageLoginParam;
import org.ljy.lotterysystem.controller.param.UserLoginParam;
import org.ljy.lotterysystem.controller.param.UserPasswordLoginParam;
import org.ljy.lotterysystem.controller.param.UserRegisterParam;
import org.ljy.lotterysystem.dao.dataobject.Encrypt;
import org.ljy.lotterysystem.dao.dataobject.UserDO;
import org.ljy.lotterysystem.dao.mapper.UserMapper;
import org.ljy.lotterysystem.service.IUserService;
import org.ljy.lotterysystem.service.dto.UserDTO;
import org.ljy.lotterysystem.service.dto.UserLoginDTO;
import org.ljy.lotterysystem.service.dto.UserRegisterDTO;
import org.ljy.lotterysystem.service.enums.UserIdentityEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *
 */

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private VerificationCodeServiceImpl verificationCodeService;

    //日志
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        //1.校验参数
        checkRegisterInfo(param);

        //2.加密数据(构造请求)
        UserDO user = new UserDO();
        //System.out.println("========="+param.getName());
        user.setUserName(param.getName());
        user.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        user.setIdentity(param.getIdentity());
        user.setEmail(param.getMail());
        if(StringUtils.hasText(param.getPassword())){ //设置密码需要判断并且进行加密
            user.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }
        //3.保存数据
        userMapper.insert(user);
        //4.数据返回
        UserRegisterDTO dto = new UserRegisterDTO();
        dto.setUserId(user.getId());
        return dto;
    }

    /**
     *  用户登陆
     * @param param
     * @return
     */
    @Override
    public UserLoginDTO login(UserLoginParam param) {
        //1.校验参数类型并转换
        UserLoginDTO userLoginDTO;
        if(param instanceof UserPasswordLoginParam userLoginParam) {
            //密码登陆
            userLoginDTO = loginByPassword(userLoginParam);
        }else if(param instanceof ShortMessageLoginParam userLoginParam) {
            //验证码登陆
            userLoginDTO = loginByShortMessage(userLoginParam);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.PARAM_ERROR);
        }
        return userLoginDTO;
    }

    /**
     * 根据人员身份返回人员列表
     * @param identity
     * @return
     */
    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identity) {
        String identityStr = identity == null?null:identity.name();
        List<UserDO> userDOList = userMapper.selectUserListByIdentity(identityStr);
        //2.转换成Service层可以接受的结果
        List<UserDTO> userDTOList = userDOList.stream()
                .map(userDO -> {
                    UserDTO userDTO = new UserDTO();
                    userDTO.setId(userDO.getId());
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setEmail(userDO.getEmail());
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
                    return userDTO;
                }).collect(Collectors.toList());
        return userDTOList;
    }

    /**
     * 完成验证码登陆
     * @param userLoginParam
     * @return
     */
    private UserLoginDTO loginByShortMessage(ShortMessageLoginParam userLoginParam) {
        UserDO userDO = null;
        if(!RegexUtil.checkMobile(userLoginParam.getLoginMobile())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_ERROR);
        }
        logger.info("UserServiceImpl:loginByShortMessage:{}", userLoginParam.getLoginMobile());
        //1.获取用户数据 （并校验身份信息）
        userDO = userMapper.selectByPhoneNumber(new Encrypt(userLoginParam.getLoginMobile()));
        if(userDO == null) {
            throw new ServiceException(ServiceErrorCodeConstants.RETURN_ERROR);
        }else if(StringUtils.hasText(userLoginParam.getMandatoryIdentity())
                &&!userLoginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //2.获取并校验验证码
        String code = verificationCodeService.getVerificationCode(userLoginParam.getLoginMobile());
        if(!userLoginParam.getVerificationCode().equalsIgnoreCase(code)) {
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
        //3.构造返回值（token）

        UserLoginDTO loginDTO = new UserLoginDTO();
        //信息
        Map<String ,Object> claim = new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        //设置
        String token = JWTUtil.genJwt(claim);
        loginDTO.setToken(token);
        loginDTO.setIdentityEnum(UserIdentityEnum.forName(userDO.getIdentity()));
        return loginDTO;
    }


    /**
     * 完成密码登陆
     * @param userLoginParam
     * @return
     */
    private UserLoginDTO loginByPassword(UserPasswordLoginParam userLoginParam) {
        UserDO userDO = null;
        //1.检验手机号或者邮箱登陆 (用于查询数据库)
        if(RegexUtil.checkMobile(userLoginParam.getLoginName())) {
            //手机号登陆
            userDO = userMapper.selectByPhoneNumber(new Encrypt(userLoginParam.getLoginName()));
        }else if(RegexUtil.checkMail(userLoginParam.getLoginName())) {
            //邮箱登录
            userDO = userMapper.selectByMail(userLoginParam.getLoginName());
        }else {
            logger.warn("loginByPassword -- UserPasswordLoginParam:{}", JacksonUtil.writeValueAsString(userLoginParam));
            throw new ServiceException(ServiceErrorCodeConstants.PARAM_ERROR);
        }
        //2.检查登陆信息 (身份信息+密码)
        if(userDO == null) {
            logger.warn("loginByPassword -- UserPasswordLoginParam:{}", userLoginParam);
            throw new ServiceException(ServiceErrorCodeConstants.RETURN_ERROR);
        }else if(StringUtils.hasText(userLoginParam.getMandatoryIdentity())
                &&!userDO.getIdentity().equalsIgnoreCase(userLoginParam.getMandatoryIdentity())) {
                //用户身份校验不通过

            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }else if(!userDO.getPassword().equals(DigestUtil.sha256Hex(userLoginParam.getPassword()))) {
            //用户密码校验不通过
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        //3.构造返回值（token）
        UserLoginDTO loginDTO = new UserLoginDTO();
        //信息
        Map<String ,Object> claim = new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        //设置
        String token = JWTUtil.genJwt(claim);
        loginDTO.setToken(token);
        loginDTO.setIdentityEnum(UserIdentityEnum.forName(userDO.getIdentity()));
        return loginDTO;
    }
    /**
     * 校验注册参数
     *
     * @param param
     */
    private void checkRegisterInfo(UserRegisterParam param) {
        if (param == null) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        //1.校验邮箱
        if (!RegexUtil.checkMail(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.EMAIL_ERROR);
        }
        //2.手机号格式
        if (!RegexUtil.checkMobile(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_ERROR);
        }
        //3.校验身份信息
        if (null == UserIdentityEnum.forName(param.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //4.校验管理员密码是否已填
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
                && !StringUtils.hasText(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }
        //5.密码校验
        if (StringUtils.hasText(param.getPassword()) && !RegexUtil.checkPassword(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //6.校验邮箱是否已被使用
        if (checkEmailUsed(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.EMAIL_USED);
        }
        //7.校验手机号是否已被使用
        if (checkPhoneUsed(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_USED);
        }
    }

    /**
     * 校验手机号是否已被使用
     *
     * @param phoneNumber
     * @return
     */
    private boolean checkPhoneUsed(String phoneNumber) {
        int count = userMapper.countByPhone(new Encrypt(phoneNumber));
        return count > 0;
    }

    /**
     * 校验邮箱是否已被使用
     * @param email
     * @return
     */
    private boolean checkEmailUsed(String email) {
        int count = userMapper.countByEmail(email);
        return count > 0;
    }

}
